npm workspaces与Monorepo管理
npm workspaces 是 NPM 原生支持的 Monorepo 方案,无需额外工具即可管理多包仓库。
npm workspaces配置
基本目录结构
JSON
my-monorepo/
├── package.json # 根配置
├── packages/
│ ├── utils/
│ │ └── package.json # @my/utils
│ ├── core/
│ │ └── package.json # @my/core
│ └── cli/
│ └── package.json # @my/cli
└── node_modules/ # 统一提升到根目录
workspaces 声明
Bash
// 根 package.json
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*"
]
}
private: true防止根包被误发布。workspaces 支持 glob 模式,也可显式列出路径数组。
初始化工作区
Bash
# 在已有项目中启用 workspaces
npm init -w packages/utils
# 从零创建 monorepo
mkdir my-monorepo && cd my-monorepo
npm init -y
# 编辑 package.json 添加 workspaces 字段
npm install
查看工作区状态
JSON
# 列出所有工作区
npm ls -a --depth=0
# 查看工作区依赖树
npm ls --all
# 查看特定工作区信息
npm query ".workspace"
npm install在根目录执行时,自动将所有工作区依赖提升到根node_modules,工作区之间通过符号链接关联。
工作区依赖管理
工作区内部依赖
Bash
// packages/core/package.json
{
"name": "@my/core",
"dependencies": {
"@my/utils": "workspace:*"
}
}
workspace:*声明对同一 monorepo 内部包的依赖- NPM 自动创建符号链接
node_modules/@my/utils -> packages/utils - 发布时
workspace:*会被替换为实际版本号
Bash
# 为特定工作区添加依赖
npm install lodash -w @my/core
# 添加开发依赖
npm install -D jest -w @my/core
外部依赖提升机制
Bash
# 查看依赖提升情况
npm ls lodash
# ├─┬ @my/core
# │ └── lodash@4.17.21
# └─┬ @my/cli
# └── lodash@4.17.21 deduped
- 多个工作区引用同一外部包时,NPM 自动提升到根
node_modules - 版本冲突时,各自安装在自己的
node_modules
工作区依赖版本一致性
JSON
# 检测版本不一致
npm ls lodash --depth=0
# 若出现多个版本,使用 dedupe 合并
npm dedupe
不同工作区依赖同一包的不同主版本会导致重复安装,增加体积。团队应约定共享依赖版本。
工作区发布配置
Bash
// packages/utils/package.json
{
"name": "@my/utils",
"version": "1.0.0",
"main": "dist/index.js",
"files": ["dist"],
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
}
发布前确认
files字段白名单,避免源码或测试文件泄露。publishConfig覆盖发布目标。
工作区脚本批量执行
批量运行脚本
Bash
# 在所有工作区执行 build
npm run build -ws
# 在指定工作区执行
npm run test -w @my/core
# 按依赖拓扑顺序执行
npm run build -ws --if-present
-ws在所有工作区执行,-w <name>在指定工作区执行。--if-present跳过未定义该脚本的工作区。
脚本执行顺序控制
Bash
# 并行执行(默认)
npm run test -ws
# 串行执行
npm run build -ws --workspaces-sort=topological
# 从特定工作区开始(含依赖)
npm run build -w @my/cli
# 自动先 build @my/utils -> @my/core -> @my/cli
工作区过滤
JSON
# 排除特定工作区
npm run test -ws --workspace-exclude @my/cli
# 使用 npm query 过滤
npm query ".workspace[name=@my/core]" --json
根脚本编排
text
// 根 package.json
{
"scripts": {
"build": "npm run build -ws",
"test": "npm run test -ws",
"clean": "npm run clean -ws && rimraf node_modules",
"lint": "npm run lint -ws --if-present"
}
}
根脚本作为统一入口,开发者无需关心工作区内部细节。CI 中直接调用根脚本即可。
要点总结
- workspaces 在根
package.json声明,支持 glob 匹配,根包必须private: true - 内部依赖用
workspace:*,NPM 自动符号链接,发布时替换为实际版本 - 外部依赖自动提升到根
node_modules,版本冲突时各自安装 -ws批量执行脚本,-w <name>执行指定工作区,--if-present跳过无脚本的工作区- 根脚本统一编排,CI 直接调用根脚本,无需感知工作区结构